package main

import (
	"crypto/rand"
	"crypto/x509/pkix"
	"encoding/pem"
	"main/gmsm/sm2"
	"main/gmsm/x509"
	"math/big"
	"net"
	"os"
	"time"
)

func GenerateCertKeySM2(host, commonName string, alternateIPs []net.IP, alternateDNS []string) {
	// 生成 SM2 密钥对
	priv, err := sm2.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

	// 生成序列号
	max := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, _ := rand.Int(rand.Reader, max)

	// 创建证书模板
	template := x509.Certificate{
		SerialNumber: serialNumber,
		Issuer: pkix.Name{
			CommonName:   commonName,
			Organization: []string{"Test"},
			Country:      []string{"CN"},
		},
		Subject: pkix.Name{
			CommonName:   commonName,
			Organization: []string{"Test"},
			Country:      []string{"CN"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(time.Hour * 24 * 365),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		BasicConstraintsValid: true,
		IsCA:                  true,
		SignatureAlgorithm:    x509.SM2WithSM3,
	//	SubjectKeyId:[]byte("1"),
	//	AuthorityKeyId:[]byte("1"),

	
	}

	// 获取公钥
	publicKey := priv.Public().(*sm2.PublicKey)

	// 生成证书
	certificateToPem, err := x509.CreateCertificateToPem(&template, &template, publicKey, priv)
	if err != nil {
		panic(err)
	}

	// 保存证书到文件
	file, err := os.Create("caSM2.crt")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	file.Write(certificateToPem)

	// 保存私钥到文件
	privateKey, err := x509.MarshalSm2UnecryptedPrivateKey(priv)
	if err != nil {
		panic(err)
	}
	block := pem.Block{
		Type:    "SM2 PRIVATE KEY",
		Headers: nil,
		Bytes:   privateKey,
	}
	file, err = os.Create("caSM2.key")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	err = pem.Encode(file, &block)
	if err != nil {
		panic(err)
	}

	// 使用生成的根证书和私钥签发下级证书
	signCert("caSM2.crt", priv, "127.0.0.1", "127.0.0.1", []net.IP{net.ParseIP("127.0.0.1")}, alternateDNS)

}

func signCert(caCertFile string, caKeyFile *sm2.PrivateKey, host, commonName string, alternateIPs []net.IP, alternateDNS []string) {
	// 加载根证书
	caCertData, err := os.ReadFile(caCertFile)
	if err != nil {
		panic(err)
	}
	block0, _ := pem.Decode(caCertData)
	if block0 == nil {
		panic("failed to parse PEM block containing the crt")
	}
	caCert, err := x509.ParseCertificate(block0.Bytes)
	if err != nil {
		panic(err)
	}

	// 加载根证书私钥

	caKey := caKeyFile

	// 生成下级证书的密钥对
	subPriv, err := sm2.GenerateKey(rand.Reader)
	if err != nil {
		panic(err)
	}

	// 生成序列号
	max := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, _ := rand.Int(rand.Reader, max)

	// 创建下级证书模板
	subTemplate := x509.Certificate{
		SerialNumber: serialNumber,
		Issuer:       caCert.Subject,
		Subject: pkix.Name{
			CommonName:   commonName,
			Organization: []string{"SubTest"},
			Country:      []string{"CN"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(time.Hour * 24 * 365),
		KeyUsage:              x509.KeyUsageDigitalSignature,
		BasicConstraintsValid: true,
		SignatureAlgorithm:    x509.SM2WithSM3,
		IssuingCertificateURL:[]string{"http://127.0.0.1:8080/caSM2.crt","aa"},

	}

	if ip := net.ParseIP(host); ip != nil {
		subTemplate.IPAddresses = append(subTemplate.IPAddresses, ip)
	} else {
		subTemplate.DNSNames = append(subTemplate.DNSNames, host)
	}

	// 添加额外的 IP 地址和 DNS 名称
	subTemplate.IPAddresses = append(subTemplate.IPAddresses, alternateIPs...)
	subTemplate.DNSNames = append(subTemplate.DNSNames, alternateDNS...)

	// 获取下级证书的公钥
	subPublicKey := subPriv.Public().(*sm2.PublicKey)

	// 使用根证书和私钥签发下级证书
	subCertificateToPem, err := x509.CreateCertificateToPem(&subTemplate,caCert,subPublicKey, caKey)
	if err != nil {
		panic(err)
	}

	// 保存下级证书到文件
	file, err := os.Create("subCert.crt")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	file.Write(subCertificateToPem)

	// 保存下级证书私钥到文件
	subPrivateKey, err := x509.MarshalSm2UnecryptedPrivateKey(subPriv)
	if err != nil {
		panic(err)
	}
	block := &pem.Block{
		Type:    "SM2 PRIVATE KEY",
		Headers: nil,
		Bytes:   subPrivateKey,
	}

	file, err = os.Create("subCert.key")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	err = pem.Encode(file, block)
	if err != nil {
		panic(err)
	}
}

func main() {
	alternateDNS := []string{"localhost"}
	GenerateCertKeySM2("127.0.0.1", "RootCA", []net.IP{net.ParseIP("127.0.0.1")}, alternateDNS)

}